package com.ying.service.order.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.ying.core.exception.CustomException;
import com.ying.core.page.PageData;
import com.ying.core.page.PageWrap;
import com.ying.core.response.ResultCode;
import com.ying.dao.order.OrderRepository;
import com.ying.po.order.*;
import com.ying.service.order.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.swing.text.html.parser.Entity;
import java.math.BigDecimal;
import java.util.*;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private SellerService sellerService;

    @Autowired
    private OrangeService orangeService;

    @Autowired
    private WrapService wrapService;

    @Autowired
    private ExpressService expressService;

    @Override
    public Integer create(Order order) {
        if (order.getId() != null) {
            Optional<Order> optional = orderRepository.findById(order.getId());
            if (optional.isPresent()) {
                throw new CustomException(ResultCode.DATA_ALREADY_EXISTED, "OrderServiceImpl.create");
            }
        }
        // 通过expressId查找express name，再通过其他信息查找准确的id
        Express express = expressService.findById(order.getExpressId());
        String expressName = express.getName();
        Integer userId = order.getUserId();
        Float weight = order.getWeight();
        String target = sellerService.findById(order.getBuyerId()).getProvince();
        String origin = sellerService.findById(order.getSellerId()).getProvince();

        Integer newExpressId = expressService.findByNameWeightTargetOrigin(expressName,weight,origin,target,userId);
        order.setExpressId(newExpressId);
        return orderRepository.save(order).getId();
    }

    @Override
    public void deleteById(Integer id) {
        // 参数检验----------------------------------
        if (id == null)
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.deleteById");
        Optional<Order> optional = orderRepository.findById(id);
        if (!optional.isPresent()) {
            throw new CustomException(ResultCode.RESULE_DATA_NONE, "OrderServiceImpl.deleteById");
        }
        // ------------开始业务----------------------
        Order order = optional.get();
        order.setIsDelete(1);
        orderRepository.save(order);
    }

    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
        // 参数检验----------------------------------
        if (CollUtil.isEmpty(ids))
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.deleteByIdInBatch");
        // ------------开始业务----------------------
        for (Integer id: ids) {
            this.deleteById(id);
        }
    }

    @Override
    public void updateById(Order order) {
        // -------------------参数检验---------------------
        if (order.getId() == null) {
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.updateById");
        }
        Optional<Order> optional = orderRepository.findById(order.getId());
        if (!optional.isPresent()) {
            throw new CustomException(ResultCode.RESULE_DATA_NONE, "OrderServiceImpl.updateById");
        }
        // ------------开始业务----------------------
        // 通过expressId查找express name，再通过其他信息查找准确的id
        Express express = expressService.findById(order.getExpressId());
        String expressName = express.getName();
        Integer userId = order.getUserId();
        Float weight = order.getWeight();
        String target = sellerService.findById(order.getBuyerId()).getProvince();
        String origin = sellerService.findById(order.getSellerId()).getProvince();

        Integer newExpressId = expressService.findByNameWeightTargetOrigin(expressName,weight,origin,target,userId);
        order.setExpressId(newExpressId);
//        order.setIsDone(0);
        order.setIsDelete(0);
        orderRepository.save(order);
    }

    @Override
    public void updateByIdInBatch(List<Order> orders) {
        // ------------------参数检验---------------
        if (CollUtil.isEmpty(orders))
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.updateByIdInBatch");
        // ------------开始业务----------------------
        for (Order order: orders) {
            this.updateById(order);
        }
    }

    @Override
    public Map<String, Object> findById(Integer id) {
        // ------------------参数检验---------------
        if (id == null)
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.findById");
        // ------------开始业务----------------------
        Optional<Order> optional = orderRepository.findByIdAndIsNotDelete(id);
        if (optional.isPresent()) {
            Map<String, Object> map = rebuildOrder(optional.get());
            return map;
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> findByIdInBatch(List<Integer> ids) {
        // ------------------参数检验---------------
        if (CollUtil.isEmpty(ids))
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.findByIdInBatch");
        // ------------开始业务----------------------
        List<Map<String, Object>> orderList = new ArrayList<Map<String, Object>>();
        for (Integer id : ids) {
            orderList.add(this.findById(id));
        }
        return orderList;
    }

    // 分页查询
    @Override
    public PageData<Map<String, Object>> findAllByPage(PageWrap pageWrap) {
        // ------------------参数检验---------------
        if (!pageWrap.check()) {
            throw new CustomException(ResultCode.PARAM_IS_BLANK, "OrderServiceImpl.findPage");
        }
        // -------------------开始业务----------------------
        Pageable pageable = PageRequest.of(pageWrap.getPage(), pageWrap.getCapacity(), pageWrap.sortMethod());
        Order order = (Order) pageWrap.getModel();
        Integer userId = order.getUserId();
        Page<Order> orderPage = orderRepository.getOrderPageIsNotDeleted(pageable, userId);
        PageData<Order> pageData = PageData.from(orderPage);
        List<Order> orderList = pageData.getRecords();
        List<Map<String, Object>> result = new ArrayList<>();
        for (Order o : orderList) {
            Map<String, Object> m = this.rebuildOrder(o);
            result.add(m);
        }
        PageData<Map<String, Object>> mapPageData = new PageData<Map<String, Object>>(pageData.getPage(), pageData.getCapacity(), pageData.getTotal(), result);
        return mapPageData;
    }

    @Override
    public Integer countAll(Integer userId, Integer year) {
        if (year == null) {
            List<Order> orderList = orderRepository.findAllIsNotDelete(userId);
            return orderList.size();
        } else {
            Integer count = 0;
            List<Order> orderList = orderRepository.findAllIsNotDelete(userId);
            for (Order o : orderList) {
                int year1 = DateUtil.year(o.getCreateTime());
                if (year1 == year) {
                    count++;
                }
            }
            return count;
        }
    }

    private Map<String, Object> rebuildOrder(Order order) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", order.getId());
        map.put("count", order.getCount());
        map.put("weight", order.getWeight());
        map.put("price", order.getPrice());
        map.put("createTime", order.getCreateTime());
        map.put("isDone", order.getIsDone());
        map.put("buyer", sellerService.findById(order.getBuyerId()));
        map.put("seller", sellerService.findById(order.getSellerId()));
        map.put("orange", orangeService.findById(order.getOrangeId()));
        map.put("express", expressService.findById(order.getExpressId()));
        map.put("wrap", wrapService.findById(order.getWrapId()));
        map.put("remark", order.getRemark());
        return map;
    }

    @Override
    public List<Map<String, Object>> findAll(Integer userId) {

        List<Order> orderList = orderRepository.findAllIsNotDelete(userId);
        List<Map<String, Object>> result = new ArrayList<>();
        for (Order o : orderList) {
            Map<String, Object> m = this.rebuildOrder(o);
            result.add(m);
        }
        return result;
    }

    @Override
    public void changeOrderStatus(Integer status, Integer orderId) {
        Optional<Order> optional = orderRepository.findById(orderId);
        if (optional.isPresent()) {
            Order order = optional.get();
            order.setIsDone(status);
            orderRepository.save(order);
        } else {
            throw new CustomException(ResultCode.RESULE_DATA_NONE, "OrderServiceImpl.changeOrderStatus");
        }
    }

    @Override
    public PageData<Map<String, Object>> queryOrderByCondition(PageWrap<Order> pageWrap) {
        Pageable pageable = PageRequest.of(pageWrap.getPage(), pageWrap.getCapacity(), pageWrap.sortMethod());
        Order model = pageWrap.getModel();
        Integer b = model.getBuyerId();
        Integer u = model.getUserId();
        Integer e = model.getExpressId();
        Integer d = model.getIsDone();

        Page<Order> orderPage = null;
        if (b == null && e == null && d == null) {
            return this.findAllByPage(pageWrap);
        } else if (b != null && e == null && d == null) {
            orderPage = orderRepository.findByBuyerId(pageable, u, b);
        } else if (b == null && e != null && d == null) {
            List<Integer> ids = expressService.findIdsByName(e, u);
            orderPage = orderRepository.finByExpressId(pageable, u, ids);
        } else if (b == null && e == null && d != null) {
            orderPage = orderRepository.finByStatus(pageable, u, d);
        } else if (b != null && e != null && d == null) {
            List<Integer> ids = expressService.findIdsByName(e, u);
            orderPage = orderRepository.findByBuyerIdAndExpressId(pageable, u, b, ids);
        } else if (b != null && e == null && d != null) {
            orderPage = orderRepository.findByBuyerIdAndStatus(pageable, u, b, d);
        } else if (b == null && e != null && d != null) {
            List<Integer> ids = expressService.findIdsByName(e, u);
            orderPage = orderRepository.findByExpressIdAndStatus(pageable, u, ids, d);
        } else if (b != null && e != null && d != null) {
            List<Integer> ids = expressService.findIdsByName(e, u);
            orderPage = orderRepository.findByBuyerIdAndExpressIdAndStatus(pageable, u, b, ids, d);
        }
        PageData<Order> pageData = PageData.from(orderPage);
        List<Order> orderList = pageData.getRecords();
        List<Map<String, Object>> result = new ArrayList<>();
        for (Order o : orderList) {
            Map<String, Object> m = this.rebuildOrder(o);
            result.add(m);
        }
        return new PageData<Map<String, Object>>(pageData.getPage(), pageData.getCapacity(), pageData.getTotal(), result);
    }

    @Override
    public List<BigDecimal> getPriceList(Integer userId) {
        List<BigDecimal> priceList = orderRepository.findByUserId(userId);
        List<BigDecimal> duplicates = new ArrayList<>();
        for (BigDecimal price : priceList) {
            if (!duplicates.contains(price)) {
                duplicates.add(price);
            }
        }
        return duplicates;
    }

    @Override
    public BigDecimal getNumberOfWeight(Integer userId,Integer year) {
        List<Order> orderList = orderRepository.findAllIsNotDeleteAndIsDone(userId);
        BigDecimal w = new BigDecimal(0);
        if (year == null) {
            for (Order order: orderList) {
                w = NumberUtil.add(w, NumberUtil.mul(order.getCount(), order.getWeight()));
            }
        } else {
            for (Order order: orderList) {
                if (DateUtil.year(order.getCreateTime()) == year) {
                    w = NumberUtil.add(w, NumberUtil.mul(order.getCount(), order.getWeight()));
                }
            }
        }
        return w;
    }

    @Override
    public Integer getNumberOfContainer(Integer userId, Integer year) {
        List<Order> orderList = orderRepository.findAllIsNotDeleteAndIsDone(userId);
        Integer count = 0;
        if (year == null) {
            for (Order order: orderList) {
                count = order.getCount() + count;
            }
        } else {
            for (Order order: orderList) {
                if (year == DateUtil.year(order.getCreateTime())) {
                    count = order.getCount() + count;
                }
            }
        }

        return count;
    }

    @Override
    public BigDecimal getNumberOfMoney(Integer userId, Integer year) {
        List<Order> orderList = orderRepository.findAllIsNotDeleteAndIsDone(userId);
        BigDecimal total = new BigDecimal(0);
        if (year == null) {
            for (Order order: orderList) {
                BigDecimal oneOrderProfit = this.calculateProfitOfOneOrder(order);
                total = NumberUtil.add(total, oneOrderProfit);
            }
        } else {
            for (Order order: orderList) {
                if (DateUtil.year(order.getCreateTime()) == year) {
                    BigDecimal oneOrderProfit = this.calculateProfitOfOneOrder(order);
                    total = NumberUtil.add(total, oneOrderProfit);
                }
            }
        }
        return total;
    }

    private BigDecimal calculateProfitOfOneOrder(Order order) {
        // 售价
        BigDecimal price = order.getPrice();
        // 成本
        Express express = expressService.findById(order.getExpressId());
        Orange orange = orangeService.findById(order.getOrangeId());
        Wrap wrap = wrapService.findById(order.getWrapId());
        BigDecimal e = NumberUtil.mul(express.getPrice(), order.getCount());
        BigDecimal o = NumberUtil.mul(orange.getPrice(), order.getWeight());
        BigDecimal w = NumberUtil.mul(wrap.getPrice(), order.getCount());
        BigDecimal oneOrderProfit = NumberUtil.sub(price, NumberUtil.add(w, e, o));
        return oneOrderProfit;
    }

    @Override
    public BigDecimal getOrderCompletion(Integer userId, Integer year) {
        List<Order> orderList = orderRepository.findAllIsNotDelete(userId);

        Integer count = 0;
        Integer total = 0;
        if (year == null) {
            total = orderList.size();
            for (Order order : orderList) {
                if (order.getIsDone() == 1) {
                    count++;
                }
            }
        } else {
            for (Order order : orderList) {
                int year1 = DateUtil.year(order.getCreateTime());
                if (year1 == year) {
                    total++;
                    if (order.getIsDone() == 1 ) {
                        count++;
                    }
                }
            }
        }
        if (total == 0) {
            return new BigDecimal(0);
        }
        BigDecimal div = NumberUtil.div(count, total);
        return NumberUtil.round(NumberUtil.mul(div, new BigDecimal(100)), 1);
    }

//  全部订单的回购率
    @Override
    public BigDecimal getOrderReBuyDegree(Integer userId) {
        HashMap<Integer, Date> map = new HashMap<>();
        List<Order> orderList = orderRepository.findAllIsNotDeleteOrderByTime(userId);
        Integer total = 0;
        Integer count = 0;
            total = orderList.size();
            for (Order order : orderList) {
                if (!map.containsKey(order.getBuyerId())) {
                    map.put(order.getBuyerId(), order.getCreateTime());
                } else {
                    // 判断日期差
                    long between = DateUtil.between(order.getCreateTime(), map.get(order.getBuyerId()), DateUnit.DAY);
                    if (between >= 1) {
                        count++;
                        map.put(order.getBuyerId(), order.getCreateTime());
                    }
                }
            }

        if (total == 0) {
            return new BigDecimal(0);
        }
        return NumberUtil.round(NumberUtil.mul(NumberUtil.div(count, total), new BigDecimal(100)), 1);
    }

    //    本年度订单的回购率
    @Override
    public BigDecimal getOrderRebuyDegreeOfThisYear(Integer userId, Integer year) {
        List<Order> orderList = orderRepository.findAllByYearAndOrderByTime(userId, year);
        Integer total = orderList.size();
        Integer count = 0;
        // 去重map
        HashMap<Object, Object> map = new HashMap<>();
        for (Order order : orderList) {
            List<Order> ol = orderRepository.findLessYear(userId, order.getBuyerId(), year);
            // 情况1：以往有，必是回购
            if (ol.size() > 0) {
                count++;
            } else {
                // 情况2：以往没有，
                // 2.1 今年是第一次买
                if (!map.containsKey(order.getBuyerId())) {
                    map.put(order.getBuyerId(), order.getCreateTime());
                } else {
                   // 2.2 今年不是第一次买
                    count++;
                }
            }
        }
        if (total == 0) {
            return new BigDecimal(0);
        }
        return NumberUtil.round(NumberUtil.mul(NumberUtil.div(count, total), new BigDecimal(100)), 1);
    }

    // 快递合作率
    @Override
    public List<Map> getExpressDegree(Integer userId, Integer year) {
        // 设计一个 expressName: count 的hash表
        HashMap<String, Integer> map = new HashMap<>();
        List<Map> nameList = expressService.getAllExpressName(userId);
        for (Map m : nameList) {
            String name = (String)m.get("name");
            map.put(name, 0);
        }
        // 对每个快递进行数量记录
        List<Order> orderList = orderRepository.findAllIsNotDeleteAndIsDone(userId);
        Integer total = 0;
        if (year == null) {
            total = orderList.size();
            for (Order order : orderList) {
                Integer expressId = order.getExpressId();
                String eName = expressService.findById(expressId).getName();
                Integer initCount = map.get(eName);
                Integer count= initCount+1;
                map.put(eName, count);
            }
        } else {
            for (Order order : orderList) {
                if (DateUtil.year(order.getCreateTime()) == year) {
                    total++;
                    Integer expressId = order.getExpressId();
                    String eName = expressService.findById(expressId).getName();
                    Integer initCount = map.get(eName);
                    Integer count= initCount+1;
                    map.put(eName, count);
                }
            }
        }

        // 将数量转成比率
        ArrayList<Map> resultList = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            HashMap<String, Object> result = new HashMap<>();
            result.put("eName", entry.getKey());
            Integer count = entry.getValue();
            result.put("eDegree", NumberUtil.round(NumberUtil.mul(NumberUtil.div(count, total), new BigDecimal(100)), 1));
            resultList.add(result);
        }
        return resultList;
    }

    @Override
    public Map getNewAndOldBuyerCountThisYear(Integer userId, Integer year) {
        HashMap<String, Object> map = new HashMap<>();
        // 新买家直接通过seller表查询
        List<Seller> newBuyerList = sellerService.findNewBuyerThisYear(userId, year);
        map.put("newBuyerList", newBuyerList);
        map.put("newBuyerCount", newBuyerList.size());
        // 旧买家，本年度订单中的所有userId除去新买家Id
        List<Integer> ids = new ArrayList<>();
        for (Seller b : newBuyerList) {
            ids.add(b.getId());
        }
        List<Integer> ids2 = orderRepository.findAllOldBuyer(userId, year);
//        System.out.println("================");
//        System.out.println(ids2.size());
        // 遍历新顾客的id表，ids2中删除这些id
        for (Integer id : ids) {
            ids2.remove(id);
        }
        List<Seller> oldBuyerList = sellerService.findByIdInBatch(ids2);
        map.put("oldBuyerList", oldBuyerList);
        map.put("oldBuyerCount", ids2.size());
        return map;
    }

    @Override
    public Map<String, List> getChartData(Integer userId, Integer year) {
        HashMap<String, List> map = new HashMap<>();
        List<Order> orderList = orderRepository.findAllByYearAndOrderByTime(userId, year);
        List<Integer> countList = new ArrayList<>();
        List<Integer> orderNumList = new ArrayList<>();
        List<Float> weightList = new ArrayList<>();
        List<String> timeLine = new ArrayList<>();

        for (Order order : orderList) {
            String timeOne = DateUtil.format(order.getCreateTime(), "MM-dd");
            if (!timeLine.contains(timeOne)) {
                timeLine.add(timeOne);
                countList.add(0);
                orderNumList.add(0);
                weightList.add(0.F);
            }
        }
        for (Order order : orderList) {
            int i = timeLine.indexOf(DateUtil.format(order.getCreateTime(), "MM-dd"));
            orderNumList.add(i, orderNumList.get(i)+1);
            orderNumList.remove(i+1);
            countList.add(i, countList.get(i) + order.getCount());
            countList.remove(i+1);
            weightList.add(i, weightList.get(i)+order.getCount()*order.getWeight());
            weightList.remove(i+1);
        }
        map.put("xAxis", timeLine);
        map.put("serialOfOrder", orderNumList);
        map.put("serialOfContainer", countList);
        map.put("serialOfWeight", weightList);
        return map;
    }
}
